using System;
using System.Threading;
using DevExpress.Xpo.DB.Exceptions;
using NUnit.Framework;
using SmartPeople.Framework.SecuritySpace;
using SmartPeople.Framework.SecuritySpace.Tests;

namespace SmartPeople.Framework.SecuritySpace.Provider.Tests
{
    [TestFixture]
    public class ProviderSecurityUserTests
    {
        //SUser_001
        [Test, Description("Creates a user.")]
        public void CreateAUser()
        {
            ISecuritySpace securitySpace = TestsHelper.GetSecuritySpace();
            securitySpace.Clear();
            securitySpace.Users.DeleteUser("User1");

            ISecurityUser user1 =
                securitySpace.Users.CreateUser(TestUsers.User1, TestUsers.User1Password, "user1suser@acme.com");
            Assert.IsNotNull(user1);
            string SavedUserName = securitySpace.Users.GetUser(user1.UserName).UserName;
            Assert.AreEqual(user1.UserName, SavedUserName);
            Assert.AreEqual(1, securitySpace.Users.Count);
            user1.Email = TestUsers.User1Email;
            user1.FullName = TestUsers.User1FullName;
            user1.Description = TestUsers.User1Description;
            user1.PasswordQuestion = "Who is you favourite teacher?";
            securitySpace.Users.UpdateUser(user1);
            string SavedUserNameByEmail = securitySpace.Users.GetUserNameByEmail(user1.Email);
            Assert.AreEqual(TestUsers.User1, SavedUserNameByEmail);


            securitySpace.Users.DeleteUser("User1");

            securitySpace.Clear();
        }

        //SUser_002
        [Test, Description("Deletes a user")]
        public void DeleteAUser()
        {
            ISecuritySpace securitySpace = TestsHelper.GetSecuritySpace();
            securitySpace.Clear();
            securitySpace.Users.DeleteUser("User1");

            ISecurityUser user1 =
                securitySpace.Users.CreateUser(TestUsers.User1, TestUsers.User1Password, "suer002user1@acme.com",
                                               "What is your fathers middle name?", "Smith", true, "user1");
            Assert.IsNotNull(user1);
            string SavedUserName = securitySpace.Users.GetUser(user1.UserName).UserName;
            Assert.AreEqual(user1.UserName, SavedUserName);
            Assert.AreEqual(1, securitySpace.Users.Count);
            user1.Email = TestUsers.User1Email;
            user1.FullName = TestUsers.User1FullName;
            user1.Description = TestUsers.User1Description;
            securitySpace.Users.UpdateUser(user1);
            string SavedUserByEmail = securitySpace.Users.GetUserNameByEmail(user1.Email);
            Assert.AreEqual(TestUsers.User1, SavedUserByEmail);
            securitySpace.Users.DeleteUser(user1.UserName);
            Assert.AreEqual(0, securitySpace.Users.Count);

            securitySpace.Users.DeleteUser("User1");
            securitySpace.Clear();
        }

        //SUser_003
        [Test, Description("User creation and deletion test combined")]
        public void CreateDeleteUserTests()
        {
            ISecuritySpace securitySpace = TestsHelper.GetSecuritySpace();
            securitySpace.Clear();
            securitySpace.Users.DeleteUser("User1");
            
            //assume all data needed to create user for first time
            ISecurityUser user1 =
                securitySpace.Users.CreateUser(TestUsers.User1, TestUsers.User1Password, "user1a@acme.com",
                                               "What is your favourite TV Show?", "Friends", true, "user1");
            Assert.IsNotNull(user1);
            string SavedUser = securitySpace.Users.GetUser(user1.UserName).UserName;
            Assert.AreEqual(user1.UserName, securitySpace.Users.GetUser(user1.UserName).UserName);
            Assert.AreEqual(1, securitySpace.Users.Count);
            user1.Email = TestUsers.User1Email;
            securitySpace.Users.UpdateUser(user1);
            string SavedUserByEmail = securitySpace.Users.GetUserNameByEmail(user1.Email);
            Assert.AreEqual(TestUsers.User1, SavedUserByEmail);
            securitySpace.Users.DeleteUser(TestUsers.User1);
            Assert.AreEqual(0, securitySpace.Users.Count);

            securitySpace.Users.DeleteUser("User1");
            securitySpace.Clear();
        }


        //SUser_004
        [Test, Description("Creates a Duplicate User")]
        public void ErrorOnDuplicateUserTest()
        {
            ISecuritySpace securitySpace = TestsHelper.GetSecuritySpace();
            securitySpace.Clear();
            securitySpace.Users.DeleteUser("User1");

            string userName = TestUsers.User1;
            ISecurityUser user1 = securitySpace.Users.CreateUser(userName, "user1b@acme.com");
            Assert.IsNotNull(user1);
            Assert.AreEqual(1, securitySpace.Users.Count);
            string userName1 = TestUsers.User1;
            MyAssert.ExpectedException(typeof (ConstraintViolationException),
                                       delegate
                                           {
                                               ISecurityUser user2 =
                                                   securitySpace.Users.CreateUser(userName1, "user1c@acme.com");
                                           },
                                       "Creating a user with same username of existing account should fail!");

            securitySpace.Users.DeleteUser("User1");
            securitySpace.Clear();
        }

        //SUser_005
        [Test, Description("Admin creates two users with same email.")]
        public void ErrorOnDuplicateEmail()
        {
            ISecuritySpace securitySpace = TestsHelper.GetSecuritySpace();
            securitySpace.Users.Clear();

            ISecurityUser user1 =
                securitySpace.Users.CreateUser(TestUsers.User1, TestUsers.User1Password, "user1d@acme.com");
            user1.Email = TestUsers.User1Email;
            user1.PasswordQuestion = "What is you fathers middle name";
            securitySpace.Users.UpdateUser(user1);
            ISecurityUser user2 =
                securitySpace.Users.CreateUser(TestUsers.User2, TestUsers.User2Password, "user1e@acme.com");
            user2.Email = TestUsers.User1Email;
            user2.PasswordQuestion = "What is you favourite car?";
            MyAssert.ExpectedException(typeof (ConstraintViolationException),
                                       delegate { securitySpace.Users.UpdateUser(user2); },
                                       "Updating with same email should fail!");


            securitySpace.Users.Clear();
        }


        //SUser_006
        [Test, Description("Admin creates user with invalid email ID.")]
        public void ErrorOnUserCreatedWithInvalidEmailID()
        {
            ISecuritySpace securitySpace = TestsHelper.GetSecuritySpace();
            securitySpace.Clear();
            securitySpace.Users.DeleteUser("User1");
            MyAssert.ExpectedException(typeof (ArgumentException),
                                       delegate
                                           {
                                               securitySpace.Users.CreateUser(TestUsers.User1, TestUsers.User1Password,
                                                                              "1johndoe@acme.com");
                                           },
                                       "Creating a user with invalid email id should fail!");
            securitySpace.Users.DeleteUser("User1");
            securitySpace.Clear();
        }


        //SUser_007
        [Test, Description("Admin creates user with a username less than minimum characters")]
        public void AdminCreatesUserWithUserNameLessThanMinChar()
        {
            ISecuritySpace securitySpace = TestsHelper.GetSecuritySpace();
            securitySpace.Clear();
            securitySpace.Users.DeleteUser("a");
            MyAssert.ExpectedException(typeof (ArgumentException),
                                       delegate { securitySpace.Users.CreateUser("a", "abcd123z"); },
                                       "Username should be more than single character");
            securitySpace.Users.DeleteUser("a");
            securitySpace.Clear();
        }


        //SUser_008
        [Test, Description("Check if user password is correct.")]
        public void UserPasswordTests()
        {
            ISecuritySpace securitySpace = TestsHelper.GetSecuritySpace();
            securitySpace.Clear();
            securitySpace.Users.DeleteUser("User4");

            ISecurityUser user4 =
                securitySpace.Users.CreateUser(TestUsers.User4, TestUsers.User4Password, "secusr4008@acme.com");
            Assert.IsNotNull(user4);
            Assert.AreEqual(TestUsers.User4Password, user4.GetPassword());

            securitySpace.Users.DeleteUser("User4");
            securitySpace.Clear();
        }

        //SUser_009
        [Test, Description("Admin changes user password")]
        public void AdminChangesUserPassword()
        {
            ISecuritySpace securitySpace = TestsHelper.GetSecuritySpace();
            securitySpace.Clear();
            securitySpace.Users.DeleteUser("User1");

            ISecurityUser user1 =
                securitySpace.Users.CreateUser(TestUsers.User1, TestUsers.User1Password, "user1susr009@acme.com");
            Assert.AreEqual(1, securitySpace.Users.Count);
            user1.ChangePassword(TestUsers.User1Password, "password1");
            Assert.AreEqual(user1.GetPassword(), "password1");

            securitySpace.Users.DeleteUser("User1");
            securitySpace.Clear();
        }

        //SUser_010
        [Test, Description("User logs in with new password changed by admin")]
        public void AdminChangesUserPasswordUserLoginWithNew()
        {
            ISecuritySpace securitySpace = TestsHelper.GetSecuritySpace();
            securitySpace.Clear();
            securitySpace.Users.DeleteUser("User1");

            ISecurityUser user1 =
                securitySpace.Users.CreateUser(TestUsers.User1, TestUsers.User1Password, "user1suser0010@acme.com");
            Assert.IsNotNull(user1);
            Assert.AreEqual(user1.UserName, securitySpace.Users.GetUser(user1.UserName).UserName);
            Assert.AreEqual(1, securitySpace.Users.Count);
            user1.IsApproved = true;
            user1.ChangePassword(TestUsers.User1Password, "john123Z");
            IToken token;
            token = securitySpace.Users.Authenticate(TestUsers.User1, "john123Z");
            Assert.IsNotNull(token, "Non approved user should fail in Authentication!.");

            securitySpace.Users.DeleteUser("User1");
            securitySpace.Clear();
        }

        //SUser_011
        [Test, Description("Admin changes user secret question and password")]
        public void AdminChangesUserSecretQuestionAndPassword()
        {
            ISecuritySpace securitySpace = TestsHelper.GetSecuritySpace();
            securitySpace.Clear();
            securitySpace.Users.DeleteUser("User1");

            ISecurityUser user1 =
                securitySpace.Users.CreateUser(TestUsers.User1, TestUsers.User1Password, "user1011sur@acme.com");
            Assert.IsNotNull(user1);
            Assert.AreEqual(user1.UserName, securitySpace.Users.GetUser(user1.UserName).UserName);
            Assert.AreEqual(1, securitySpace.Users.Count);
            user1.ChangePassword(TestUsers.User1Password, "password1");
            Assert.AreEqual(user1.GetPassword(), "password1");
            user1.ChangePasswordQuestionAndAnswer(user1.GetPassword(), "What is your pets name?", "pluto");
            Assert.AreEqual(user1.PasswordQuestion, "What is your pets name?");

            securitySpace.Users.DeleteUser("User1");
            securitySpace.Clear();
        }


        //SUser_012
        [Test, Description("Admin creates a user with no secret question.")]
        public void AdminCreatesUserWithNoSecretQuestion()
        {
            ISecuritySpace securitySpace = TestsHelper.GetSecuritySpace();
            securitySpace.Clear();
            securitySpace.Users.DeleteUser("User1");

            ISecurityUser user1 =
                securitySpace.Users.CreateUser(TestUsers.User1, TestUsers.User1Password, "user1012sur@acme.com");
            Assert.IsNotNull(user1);
            Assert.AreEqual(user1.UserName, securitySpace.Users.GetUser(user1.UserName).UserName);
            Assert.AreEqual(1, securitySpace.Users.Count);
            user1.Email = TestUsers.User1Email;
            user1.FullName = TestUsers.User1FullName;
            user1.Description = TestUsers.User1Description;
            MyAssert.ExpectedException(typeof (ArgumentException),
                                       delegate { securitySpace.Users.UpdateUser(user1); },
                                       "No secret question assigned to user!");

            securitySpace.Users.DeleteUser("User1");
            securitySpace.Clear();
        }


        //SUser_013
        [Test, Description("Admin approves a user")]
        public void AdminApprovesAUser()
        {
            ISecuritySpace securitySpace = TestsHelper.GetSecuritySpace();
            securitySpace.Clear();
            securitySpace.Users.DeleteUser("User1");

            ISecurityUser user1 =
                securitySpace.Users.CreateUser(TestUsers.User1, TestUsers.User1Password, "susr013user1@acme.com");
            user1.IsApproved = true;
            Assert.AreEqual(user1.IsApproved, true);

            securitySpace.Users.DeleteUser("User1");
            securitySpace.Clear();
        }

        //SUser_014
        [Test]
        [Description("Admin disapproves a user who was already approved")]
        public void AdminDissaprovesAnApprovedUser()
        {
            ISecuritySpace securitySpace = TestsHelper.GetSecuritySpace();
            securitySpace.Clear();
            securitySpace.Users.DeleteUser("User1");

            ISecurityUser user1 =
                securitySpace.Users.CreateUser(TestUsers.User1, TestUsers.User1Password, "user1suser014@acme.com");
            Assert.IsNotNull(user1);
            Assert.AreEqual(user1.UserName, securitySpace.Users.GetUser(user1.UserName).UserName);
            Assert.AreEqual(1, securitySpace.Users.Count);
            user1.IsApproved = true;
            Assert.AreEqual(user1.IsApproved, true);
            user1.IsApproved = false;
            Assert.AreEqual(user1.IsApproved, false);

            securitySpace.Users.DeleteUser("User1");
            securitySpace.Clear();
        }

        //SUser_015
        //[Ignore("This test needs correction")]
        [Test, Description("Authenticate tests.")]
        public void AuthenticateTests()
        {
            ISecuritySpace securitySpace = TestsHelper.GetSecuritySpace();
            securitySpace.Clear();
            securitySpace.Users.DeleteUser("User1");

            ISecurityUser user =
                securitySpace.Users.CreateUser(TestUsers.User1, TestUsers.User1Password, "user1015suser@acme.com");
            Assert.IsNotNull(user, "User not created.");
            Assert.AreEqual(1, securitySpace.Users.Count);
            IToken token;
            token = securitySpace.Users.Authenticate(TestUsers.User1, TestUsers.User1Password);
            Assert.IsNull(token, "Non approved user should fail in Authentication!.");
            user.IsApproved = true;
            user.PasswordQuestion = "What is your favourite pet";
            securitySpace.Users.UpdateUser(user);
            token = securitySpace.Users.Authenticate(TestUsers.User1, TestUsers.User1Password);
            Assert.IsNotNull(token, "Approved user should success in Authentication!.");
            ISecurityUser userVerify = securitySpace.Users.GetUser(token, false);
            Assert.IsNotNull(userVerify, "User not retrived by it's token");
            Assert.AreEqual(TestUsers.User1, userVerify.UserName, "Wrong user retrived by it's token");

            securitySpace.Users.DeleteUser("User1");
            securitySpace.Clear();
        }

        //SUser_016
        [Test, Description("Checks if authenticated user is shown status online after login.")]
        public void CheckIfAuthenticatedUserOnline()
        {
            ISecuritySpace securitySpace = TestsHelper.GetSecuritySpace();
            securitySpace.Clear();
            securitySpace.Users.DeleteUser("User1");

            ISecurityUser user =
                securitySpace.Users.CreateUser(TestUsers.User1, TestUsers.User1Password, "user1016sur@acme.com");
            user.PasswordQuestion = "What is your fathers middle name?";
            user.IsApproved = true;
            securitySpace.Users.UpdateUser(user);
            securitySpace.Users.Authenticate(TestUsers.User1, TestUsers.User1Password);
            Assert.AreEqual(user.IsOnline, true);

            securitySpace.Users.DeleteUser("User1");
            securitySpace.Clear();
        }

        //SUser_017
        [Test, Description("Check user last activity is recorded properly.")]
        public void LastActivityDateTests()
        {
            ISecuritySpace securitySpace = TestsHelper.GetSecuritySpace();
            securitySpace.Clear();
            securitySpace.Users.DeleteUser("User1");

            ISecurityUser user1 = securitySpace.Users.CreateUser(TestUsers.User1, "user1f@acme.com");
            DateTime xlastActivityDate = user1.LastActivityDate;
            Thread.Sleep(100);
            user1 = securitySpace.Users.GetUser(user1.UserName, true);
            Assert.Greater(user1.LastActivityDate, xlastActivityDate);
            securitySpace.Users.DeleteUser(TestUsers.User1);
            Assert.IsFalse(securitySpace.Users.UserExists(TestUsers.User1));
            securitySpace.Users.DeleteUser(TestUsers.User1);
            Assert.IsFalse(securitySpace.Users.UserExists(TestUsers.User1));

            securitySpace.Users.DeleteUser("User1");
            securitySpace.Clear();
        }

        //SUser_018
        [Test]
        public void PasswordQuestionAnswerTests()
        {
            ISecuritySpace securitySpace = TestsHelper.GetSecuritySpace();
            securitySpace.Clear();
            securitySpace.Users.DeleteUser("monzer");

            string userName = "monzer";
            ISecurityUser user =
                securitySpace.Users.CreateUser(userName, "pass#123", "monzeremam@yahoo.com",
                                               "what is your programming language?", "C#", false,
                                               "user created for testing");
            IToken token;
            token = securitySpace.Users.Authenticate(userName, "pass#123");
            Assert.IsNull(token, "Non approved user should fail in Authentication!.");
            user.IsApproved = true;
            securitySpace.Users.UpdateUser(user);
            token = securitySpace.Users.Authenticate(userName, "pass#123");
            Assert.IsNotNull(token, "Approved user should success in Authentication!.");
            ISecurityUser userVerify = securitySpace.Users.GetUser(token, false);
            Assert.IsNotNull(userVerify, "User not retrived by it's token");
            Assert.AreEqual(userVerify.UserName, user.UserName);
            securitySpace.Users.DeleteUser(userName, true);

            securitySpace.Users.DeleteUser("monzer");
            securitySpace.Clear();
        }

        //SUser_019
        [Test, Description("A user who is not approved tries to login.")]
        public void NonApprovedUserTrysToLogin()
        {
            ISecuritySpace securitySpace = TestsHelper.GetSecuritySpace();
            securitySpace.Clear();
            securitySpace.Users.DeleteUser("User1");

            ISecurityUser user1 =
                securitySpace.Users.CreateUser(TestUsers.User1, TestUsers.User1Password, "user1019sur@acme.com");
            user1.IsApproved = false;
            Assert.AreEqual(user1.IsApproved, false);
            string CurrentPassword = user1.GetPassword();
            Assert.IsNull(securitySpace.Users.Authenticate(user1.UserName, user1.GetPassword()));

            securitySpace.Users.DeleteUser("User1");
            securitySpace.Clear();
        }


        //SUser_020
        [Test, Description("Old Password entered is invalid")]
        public void InvalidOldPassword()
        {
            ISecuritySpace securitySpace = TestsHelper.GetSecuritySpace();
            securitySpace.Clear();
            securitySpace.Users.DeleteUser("User1");

            ISecurityUser user1 =
                securitySpace.Users.CreateUser(TestUsers.User1, TestUsers.User1Password, "user1susr009@acme.com");
            Assert.AreEqual(1, securitySpace.Users.Count);
            //=usr1pass
            MyAssert.ExpectedException(typeof (ArgumentException),
                                       delegate { user1.ChangePassword("usr2pass", "password1"); },
                                       "Old Password entered is not valid!");

            securitySpace.Users.DeleteUser("User1");
            securitySpace.Clear();
        }

        [Test, Description("Is Password Correct for Secret Answer")]
        public void IsPasswordCorrectForSecretAnswer()
        {
            ISecuritySpace securitySpace = TestsHelper.GetSecuritySpace();
            securitySpace.Clear();
            securitySpace.Users.DeleteUser("User1");

            ISecurityUser user1 =
                securitySpace.Users.CreateUser(TestUsers.User1, TestUsers.User1Password, "user1susr009@acme.com",
                                               "What is your madien name?", "Maggie", true, "test user1");
            Assert.AreEqual(1, securitySpace.Users.Count);
            string CurrentUser = securitySpace.Users.GetUser(TestUsers.User1).GetPassword("Maggie");
            Assert.AreEqual(TestUsers.User1Password, CurrentUser);

            securitySpace.Clear();
        }



        [Test, Description("User is offline")]
        public void IsOnlineTests()
        {
            ISecuritySpace securitySpace = TestsHelper.GetSecuritySpace();
            securitySpace.Clear();
            securitySpace.Users.DeleteUser("User1");

            ISecurityUser user =
                securitySpace.Users.CreateUser(TestUsers.User1, TestUsers.User1Password, "user1016sur@acme.com",
                                               "What is your favourite color?", "Red");
            //admin has to aprove the user !
            user.IsApproved = true;
            securitySpace.Users.UpdateUser(user);
            securitySpace.Users.Authenticate(TestUsers.User1, TestUsers.User1Password);
            Assert.AreEqual(user.IsOnline, false);

            securitySpace.Users.DeleteUser("User1");
            securitySpace.Clear();
        }
    }
}